﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using Microsoft.Practices.Prism.Regions;
using Tanmia.Basis.View;

namespace Tanmia.Basis.Prism
{
    public class WindowRegionBehavior : IRegionBehavior
    {
        private readonly WeakReference ownerWeakReference;
        private WeakReference regionWeakReference;
        private readonly Style windowStyle;

        public WindowRegionBehavior(Window owner, Style windowStyle)
        {
            ownerWeakReference = new WeakReference(owner);
            this.windowStyle = windowStyle;
        }

        #region IRegionBehavior Members

        public void Attach()
        {
            IRegion region = regionWeakReference.Target as IRegion;

            if (region != null)
            {
                region.Views.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Views_CollectionChanged);
                region.ActiveViews.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ActiveViews_CollectionChanged);
            }
        }

        public IRegion Region
        {
            get { return regionWeakReference.Target as IRegion; }
            set { regionWeakReference = new WeakReference(value); }
        }

        #endregion

        public void Detach()
        {
            IRegion region = regionWeakReference.Target as IRegion;

            if (region != null)
            {
                region.Views.CollectionChanged -= Views_CollectionChanged;
                region.ActiveViews.CollectionChanged -= ActiveViews_CollectionChanged;
            }
        }

        private void ActiveViews_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Window owner = ownerWeakReference.Target as Window;

            if (owner == null)
            {
                Detach();
                return;
            }

            if (e.Action == NotifyCollectionChangedAction.Add)
                foreach (object view in e.NewItems)
                {
                    Window window = GetContainerWindow(owner, view);

                    if (window != null && !window.IsFocused)
                    {
                        window.WindowState = WindowState.Normal;
                        window.Activate();
                    }
                }
        }

        private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Window owner = ownerWeakReference.Target as Window;

            if (owner == null)
            {
                Detach();
                return;
            }

            if (e.Action == NotifyCollectionChangedAction.Add)
                foreach (object view in e.NewItems)
                {
                    EditorWindow window = new EditorWindow();
                    FrameworkElement fe = view as FrameworkElement;

                    //window.Activated += new EventHandler(window_Activated);
                    //window.Deactivated += new EventHandler(window_Deactivated);
                    //if (this.windowStyle != null)
                    //    window.Style = this.windowStyle;
                    window.Height = fe.Height + 80;
                    window.EditorUserControl = fe;
                    window.DataContext = fe.DataContext;
                    window.Closed += new EventHandler(window_Closed);
                    window.Owner = owner;
                    PopulateCommands(window, fe.DataContext);
                    window.Show();
                }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
                foreach (object view in e.OldItems)
                {
                    BaseWindow window = GetContainerWindow(owner, view);

                    if (window != null)
                    {
                        window.Close();
                        window.Content = null;
                    }
                }
        }

        private void PopulateCommands(EditorWindow target, object viewModel)
        {
            var commandProperties = viewModel.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
                .Where(x => x.PropertyType == typeof(ICommand));

            UICommand uiCmd = null;
            List<UICommand> commands = new List<UICommand>();

            foreach (PropertyInfo propInfo in commandProperties)
            {
                uiCmd = propInfo.GetValue(viewModel, null) as UICommand;
                if (uiCmd != null)
                    commands.Add(uiCmd);
            }
            commands.Sort((x, y) => x.Order - y.Order);

            int currentGroup = 1;
            for (int i = 0; i < commands.Count; i++)
            {
                uiCmd = commands[i];

                if (uiCmd.Group != currentGroup)
                {
                    currentGroup = uiCmd.Group;
                    if (i <= commands.Count - 1)
                    {
                        target.AddSeparator();
                    }
                }

                if (i == 0)
                    target.AddFirstUICommand(uiCmd);
                else if (i == commands.Count - 1)
                    target.AddLastUICommand(uiCmd);
                else
                    target.AddUICommand(uiCmd);
            }
        }

        private EditorWindow GetContainerWindow(Window owner, object view)
        {
            foreach (Window window in owner.OwnedWindows)
                if (window as EditorWindow != null)
                    if ((window as EditorWindow).EditorUserControl == view)
                        return window as EditorWindow;

            return null;
        }

        private void window_Closed(object sender, EventArgs e)
        {
            EditorWindow window = sender as EditorWindow;
            IRegion region = regionWeakReference.Target as IRegion;

            if (window != null && region != null)
                if (region.Views.Contains(window.Content))
                {
                    region.Remove(window.Content);
                    window.Content = null;
                }
        }

        private void window_Deactivated(object sender, EventArgs e)
        {
            EditorWindow window = sender as EditorWindow;
            IRegion region = regionWeakReference.Target as IRegion;

            if (window != null && region != null)
                region.Deactivate(window.Content);
        }

        private void window_Activated(object sender, EventArgs e)
        {
            IRegion region = regionWeakReference.Target as IRegion;
            EditorWindow window = sender as EditorWindow;

            if (window != null && !region.ActiveViews.Contains(window.Content))
                region.Activate(window.Content);
        }
    }
}
